package xin.nick.system.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import xin.nick.common.core.constant.SystemConstants;
import xin.nick.system.domain.dto.LoginDTO;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 基于JSON的登录方式
 * @author Nick
 * @since 2024/2/26
 */
@Slf4j
public class JsonLoginFilter extends UsernamePasswordAuthenticationFilter {

    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(SystemConstants.LOGIN_PATH,
            HttpMethod.POST.name());

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        //  重写 attemptAuthentication ,通过JSON方式获取值,进行登录

        // 只处理 POST 请求, 且 APPLICATION_JSON_VALUE 的
        String contentType = request.getContentType();
        if (DEFAULT_ANT_PATH_REQUEST_MATCHER.matches(request)
                && (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType)
                    || MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(contentType))) {

            String username = "";
            String password = "";

            // 尝试从 body 获取登录信息
            LoginDTO loginDTO = getLoginDtoFromRequest(request);
            if (Objects.nonNull(loginDTO)) {
                username = loginDTO.getUsername();
                password = loginDTO.getPassword();
                // tips 这里可以补充验证码处理逻辑
            }

            username = (username != null) ? username.trim() : "";
            password = (password != null) ? password : "";

            UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
                    password);
            // Allow subclasses to set the "details" property
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);

        }

        return super.attemptAuthentication(request, response);

    }

    /**
     * 从Request body 获取 json数据的登录信息
     * @param request
     * @return
     */
    private LoginDTO getLoginDtoFromRequest(HttpServletRequest request) {

        String bodyString = null;
        try {
            bodyString = new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(Collectors.joining());
        } catch (IOException e) {
            log.error("尝试从Request获取登录信息失败", e);
        }

        if (StrUtil.isBlank(bodyString)) {
            return null;
        }

        return JSON.parseObject(bodyString, LoginDTO.class);
    }

}
